﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Service.Model
{
    // TODO Cache metadata thread-safe.

    public static class FederationMetadataProvider
    {
        /// <summary>
        /// Gets the federation distribution key values from the set of properties' vaules.
        /// </summary>
        /// <param name="propertyValues">Available values.</param>
        /// <param name="keyNames">Distribution key properties' names.</param>
        /// <returns>The list of key values. This list may miss some values.</returns>
        public static IEnumerable<PropertyValue> GetKeyValues(IDictionary<string, PropertyValue> propertyValues, IEnumerable<string> keyNames)
        {
            foreach (var keyName in keyNames)
            {
                PropertyValue val;
                if (propertyValues.TryGetValue(keyName, out val))
                    yield return val;
                else
                    yield break;
            }
        }

        /// <summary>
        /// Gets the list of entity federation distribution key fields.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns>Names of properties. Order has a meaning.</returns>
        public static IList<string> GetFederationKeyProperties(Type entityType)
        {
            var attrs = entityType.GetCustomAttributes(typeof(FederationKeyAttribute), true);
            if (attrs.Length == 0)
                return new string[0];


            return ((FederationKeyAttribute)attrs[0]).Key.Split(',', ' ');
        }

        /// <summary>
        /// Finds out whether an entity collection storied in the federation root database also.
        /// </summary>
        /// <param name="entityType">The entity type.</param>
        /// <returns><c>true</c> if the entity can be retrieved from the root database.</returns>
        public static bool IsRootEntity(Type entityType)
        {
            var attrs = entityType.GetCustomAttributes(typeof(FederationRootAttribute), true);
            return attrs.Length > 0;
        }
    }

    /// <summary>
    /// Marks an entity type as a root collection of the federation.
    /// This means that all collection items are duplicated in the federation root table.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false) ]
    public sealed class FederationRootAttribute: Attribute
    {
    }

    /// <summary>
    /// Allows to specify names of fields used as distribution key.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false) ]
    public sealed class FederationKeyAttribute: Attribute
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="key">Comma separated list of properties' names. Order is important.</param>
        public FederationKeyAttribute(string key)
        {
            Key = key;
        }

        /// <summary>
        /// Comma separated list of properties' names. Order is important.
        /// </summary>
        public string Key { get; private set; }
    }

	/// <summary>
	/// Represents a property/value pair.
	/// </summary>
	public struct PropertyValue
	{
		/// <summary>
		/// Property info.
		/// </summary>
		public PropertyInfo Property;
		/// <summary>
		/// Property value.
		/// </summary>
		public object Value;
	}

}